/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package predictor;

import dataanalysis.Model;
import java.io.File;
import java.util.List;
import javax.swing.SwingWorker;
import weka.classifiers.Classifier;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.Utils;
import weka.core.converters.CSVSaver;

/**
 *
 * @author Administrator
 */
public class MainApp {

    private final MainView m_mainView;
    private final MainDocument m_mainDocument;
    private PredictSwingWorker m_worker;

    /**
     * @param args the command line arguments
     */
    public MainApp() {
        //显示程序启动画面
        SplashWindow splash = new SplashWindow("src\\predictor\\gui\\img\\splash.jpg");
        splash.setVisible(true);

        LookAndFeel.setLookAndFeel();
        m_mainView = new MainView(this);
        m_mainDocument = new MainDocument(this);

        //退出程序启动画面
        splash.setVisible(false);
        splash.dispose();
    }

    public boolean checkModelCapabilities(Model model) {
        Instances curData = m_mainDocument.getCurInstances();

        if (curData == null) {
            return false;
        }
        Instances trainHeader = model.getDataHeader();
        if (trainHeader == null) {
            return false;
        }
        if (curData.classIndex() != -1) {
            if (trainHeader.numAttributes() != curData.numAttributes()
                    || !trainHeader.classAttribute().equals(curData.classAttribute())) {
                return false;
            }
        } else {
            if (trainHeader.numAttributes() != curData.numAttributes() + 1) {
                return false;
            }
        }

        int m = 0, n = 0;
        while (m < curData.numAttributes() && n < trainHeader.numAttributes()) {
            if (curData.classIndex() == m) {
                m++;
                continue;
            }
            if (trainHeader.classIndex() == n) {
                n++;
                continue;
            }
            if (!(curData.attribute(m).equals(trainHeader.attribute(n)))) {
                return false;
            }
            m++;
            n++;
        }
        return true;
    }

    public void openNewDataFile() {
        try {
            Instances data = m_mainView.getLoaderData();
            if (data == null) {
                return;
            }
            m_mainView.setStatusTxt("正在打开数据...");
            String fullName = m_mainView.getLoaderFileName();
            m_mainDocument.openNewInstances(data);
            m_mainView.openNewInstances(data);
            m_mainDocument.setFullFileName(fullName);
            m_mainView.setStatusTxt("准备就绪");
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex);
        }
    }

    public boolean isModified() {
        return m_mainDocument.getModifyFlag();
    }

    public void cancleWorker() {
        if (!m_worker.isDone()) {
            m_worker.cancel(true);
        }
    }

    class PredictSwingWorker extends SwingWorker<Instances, Integer> {

        final Model m_model;
        double m_correct = 0;

        public PredictSwingWorker(final Model model) {
            m_model = model;
        }

        private Instances startPredictByModel(Model model) {
            try {
                double[] probdist = null;
                double pred = 0;
                Classifier classifier = model.getClassifier();
                Instances data = m_mainDocument.getCurInstances();
                FastVector myNewClassVector = new FastVector();
                Attribute classAtt = (Attribute) model.getDataHeader().classAttribute().copy("预测值");
                myNewClassVector.addElement(classAtt);
                Instances predClassInstances = new Instances(data.relationName(), myNewClassVector, data.numInstances());
                int classIndex = data.classIndex();

                long begin = 0;
                for (int i = 0; i < data.numInstances(); i++) {
                    Instance inst = data.instance(i);
                    double[] val = new double[1];
                    if (model.getDataHeader().classAttribute().isNominal()) {
                        probdist = classifier.distributionForInstance(inst);
                        pred = (double) Utils.maxIndex(probdist);
                        if (probdist[(int) pred] <= 0.0) {
                            pred = Instance.missingValue();
                        }

                        val[0] = (int) pred;
                        if (classIndex != -1 && val[0] == data.instance(i).value(classIndex)) {
                            m_correct++;
                        }

                    } else {
                        pred = classifier.classifyInstance(inst);
                        val[0] = pred;
                        if (classIndex != -1) {
                            double actrual = data.instance(i).value(classIndex);
                            m_correct += 1 - Math.abs(actrual - pred) / actrual;
                        }

                    }
                    predClassInstances.add(new Instance(inst.weight(), val));


                    int n = (int) ((i + 1) * 1.0 / data.numInstances() * 100);
                    if (n > (int) (i * 1.0 / data.numInstances() * 100)) {
                        long end = System.currentTimeMillis();
                        publish(n);
                        if (end - begin < 12) {
                            Thread.sleep(12 - end + begin);
                        }
                        begin = end;
                    }
                }
                Instances resultData = Instances.mergeInstances(data, predClassInstances);
                resultData.setClassIndex(data.classIndex());
                return resultData;
            } catch (Exception ex) {
                ex.printStackTrace();
                m_mainView.showErrorDlg(ex);
                return null;
            }
        }

        @Override
        protected Instances doInBackground() throws Exception {
            return startPredictByModel(m_model);
        }

        @Override
        protected void process(List<Integer> chunks) {
            super.process(chunks);
            for (int i : chunks) {
                m_mainView.setProgress(i);
            }
        }

        @Override
        protected void done() {
            super.done();
            try {
                Instances data = get();
                m_mainDocument.setResultData(data);
                m_mainDocument.setModifyFlag(true);
                m_mainView.setResultData(data);
                m_mainView.setProgress(100);

                double p = (int) (m_correct / data.numInstances() * 10000) * 1.0 / 100;
                m_mainView.setCorrectPercent(p + "%");
                m_mainView.showProcessDlg(false);
                m_mainView.setStatusTxt("准备就绪");
            } catch (Exception ex) {
                ex.printStackTrace();
                m_mainView.showErrorDlg(ex);
            }
        }
    }

    public void runDataPredictThread(final Model model) {
        m_worker = new PredictSwingWorker(model);
        m_mainView.setStatusTxt("正在预测...");
        m_worker.execute();
        m_mainView.showProcessDlg(true);
    }

    public void setDataClassIndex(int i) {
        m_mainDocument.setDataClassIndex(i);

    }
//返回是否确定保存

    public boolean saveResultData() {
        try {
            if (!m_mainView.showSaveDlg()) {
                return false;
            }
            Instances data = m_mainDocument.getResultData();
            if (data == null) {
                return true;
            }
            CSVSaver saver = new CSVSaver();
            File currFile = saver.retrieveFile();
            String filename = m_mainView.getSavePath();
            if ((currFile == null) || (!currFile.getAbsolutePath().equals(filename))) {
                saver.setFile(new File(filename));
            }
            saver.setInstances(data);
            saver.writeBatch();
            m_mainDocument.setModifyFlag(false);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex);
            return true;
        }
    }

    private void run() {
        m_mainView.showWindow();
    }

    public static void main(String[] args) {
        new MainApp().run();
    }
}
